package de.micromata.icalour;

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Font;
import java.awt.FontFormatException;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.RenderingHints;
import java.awt.geom.RoundRectangle2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.LinkedList;
import java.util.Locale;

import net.fortuna.ical4j.model.component.VEvent;

import org.apache.commons.lang.ArrayUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;

/*
 * Settings for Kodak Digital Frame W820
 * 800 x 480 pixel
 * 
 */

/**
 * This class controls the drawing commands.
 * Access to the date give the DigitalFrame object.
 * The BufferedImage contains a Graphics2D element, which is used for draw commands.
 * Time and summaray of found events will be drawed on the BufferedImage
 */
public class Drawing {

	private static Logger LOG = Logger.getRootLogger();
	private static SimpleDateFormat timeFormat = new SimpleDateFormat("HH:mm", Locale.GERMAN);
	private static SimpleDateFormat dateFormat = new SimpleDateFormat("EEEE, dd.MM.yy", Locale.GERMAN);
	private static SimpleDateFormat dateAndMonthFormat = new SimpleDateFormat("dd.MM.", Locale.GERMAN);

	private static int width = 800;
	private static int height = 480;

	// better overview in the the documentation on this site:
	// http://labs.micromata.de/display/icalour/Implementation#Implementation-{{DrawingCommands}}
	private static Point datePosition = new Point(110, 50); // position of today's date
	private static Point timePosition = new Point(220, 100); // position of today's time
	//here starts dynamic content (event time and event summary)
	private static Point contentStartPosition = new Point(100, 200); 
	private static int contentPadding = 190; // vertical position of event summary
	private static int rightPadding = 110;

	// width of maximal content
	private static int maxContentDescriptionWidth = 
			width	- (int) contentStartPosition.getX() - contentPadding - rightPadding;

	// drawing start positions
	static int bottomPadding = 10;
	static int leftPadding = contentStartPosition.x;
	static int descriptionPadding = leftPadding + contentPadding;

	/**
	 * @param bufferImg
	 * 		source image
	 * @param dframe
	 * 		Object with the data
	 * @param absolutePath
	 * 		file system path of the web application
	 */
	public static void drawContent(BufferedImage bufferImg, DigitalFrame dframe, String absolutePath) {

		/*
		 *  load local fonts
		 */
		File fontFile = new File(absolutePath + "/WEB-INF/classes/TSaOf.ttf");
		File boldFontFile = new File(absolutePath	+ "/WEB-INF/classes/TSaOf_bold.ttf");
		FileInputStream fis;
		Font font = null;
		Font boldFont = null;
		try {
			fis = new FileInputStream(fontFile);
			font = Font.createFont(Font.TRUETYPE_FONT, fis);
			fis = new FileInputStream(boldFontFile);
			boldFont = Font.createFont(Font.TRUETYPE_FONT, fis);
		} catch (FontFormatException e1) {
			LOG.error("Wrong font format");
			e1.printStackTrace();
		} catch (IOException e1) {
			LOG.error("Font file not found");
			e1.printStackTrace();
		}

		/*
		 *  define font styles
		 */
		Font eventDescriptionFont = font.deriveFont(Font.PLAIN, 30);
		Font eventTimeFont = boldFont.deriveFont(Font.BOLD, 30);
		Font timeFont = boldFont.deriveFont(Font.BOLD, 45);
		Font longDateFont = boldFont.deriveFont(Font.BOLD, 36);
		int fontSize = Math.max(eventDescriptionFont.getSize(), eventTimeFont.getSize());
		int lineHeight = fontSize + 5; // space between two lines from one event
		int lineHeightSpace = 10; // space between the events
		int topPadding = contentStartPosition.y;
		
		// current time
		java.util.Calendar now = java.util.Calendar.getInstance();
		dframe.init(now);

		// get Graphics2D to use draw commands
		Graphics2D g2d = bufferImg.createGraphics();
		// set anti aliasing for geometry and text
		g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
		g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,	RenderingHints.VALUE_ANTIALIAS_ON);
		g2d.setColor(Color.WHITE);

		// draw current date
		g2d.setFont(longDateFont);
		g2d.drawString("" + dateFormat.format(now.getTime()), datePosition.x,	datePosition.y);
		// draw current time
		g2d.setFont(timeFont);
		g2d.drawString("" + timeFormat.format(now.getTime()), timePosition.x, timePosition.y);

		// draw message if no events was found
		if (dframe.empty()) {
			g2d.setFont(eventDescriptionFont);
			g2d.drawString("keine Termine für den heutigen Tag gefunden",	leftPadding, topPadding + 100);
		}

		// drawing content
		for (int i=0; i<dframe.getSize(); i++) {
			
			// get current event from sorted event list
			VEvent event = dframe.getVEvent(i);
			String eventTime = timeFormat.format(dframe.getEventStartDate(event).getTime()) 
					+ " - " + timeFormat.format(dframe.getEventEndDate(event).getTime());

			// set font to calculate the multiLines
			g2d.setFont(eventDescriptionFont);
			String summary = event.getSummary().getValue(); // get the description/summary

			// show date if the event is take place more than one day
			if (dframe.greaterThanOneDay(event)) {
				String dateAndMonth = "/("
						+ dateAndMonthFormat.format(dframe.getEventStartDate(event).getTime()) + " - "
						+ dateAndMonthFormat.format(dframe.getEventEndDate(event).getTime()) + ")";
				summary += dateAndMonth;
			}

			// break the text: summary with the current Font, if the width is more than maxContentDescriptionWidth
			LinkedList<String> multiLines = Utils.breakText(g2d.getFontMetrics(),	summary, maxContentDescriptionWidth);
			
			// check if the summaray fit into the space (it will only display 3 lines max.)
			int nextTopPaddingPosition = (Math.min(multiLines.size(), 3) - 1)	* lineHeight + topPadding;
			if (nextTopPaddingPosition >= (height - bottomPadding)) {
				LOG.info("event summaray position is out of bounds: " + nextTopPaddingPosition);
				break;
			}
			// draw event time
			g2d.setFont(eventTimeFont);
			g2d.drawString(eventTime, leftPadding, topPadding);

			/*
			 * draw summaray, 
			 */
			g2d.setFont(eventDescriptionFont);
			int lineCount = 0;
			for (String line : multiLines) {
				lineCount++;
				// if the text have more than 3 lines, cut the last word of the
				// 3th line and print "..."
				if (lineCount == 3 && multiLines.size() > 3) {
					String[] words = line.split(" ");
					ArrayUtils.remove(words, words.length - 1); // remove last word
					line = StringUtils.join(words, ' ') + " ..."; // join words and append
																												// "..."
					// draw summary
					g2d.drawString(line, descriptionPadding, topPadding);
					topPadding += lineHeight;
					break;
					
				} else {
					// if the text don't have more than 3 lines draw summary
					g2d.drawString(line, descriptionPadding, topPadding);
					topPadding += lineHeight;
				}
			}

			/*
			 * draw a rectangle around the event which taking place now
			 */
			if (dframe.eventTakingPlaceNow(event)) {
				int roundedCorner = 50;
				// wihtout that space, the bottom of the rectangle would draw under the
				// baseline of the text
				int descender = (int) (fontSize * 0.25);

				// draw rectangle around time and summary
				RoundRectangle2D r2 = new RoundRectangle2D.Double(
						leftPadding - 10, contentStartPosition.y - fontSize,
						width	- ((leftPadding + rightPadding) - 35), 
						(lineHeight / 2	+ ((lineCount - 1) * lineHeight) + descender + lineHeight / 2),
						roundedCorner, roundedCorner);
				g2d.setStroke(new BasicStroke(3));
				g2d.draw(r2);
			}

			topPadding += lineHeightSpace; // space for next event
			if (topPadding >= (height - bottomPadding)) {
				LOG.info("bottomPadding overflow, no more events will draw");
				// draw no more events, because there is not enough space anymore
				break;
			}
		}
		g2d.dispose(); // release resource

	}
}
